# -*- coding: iso-8859-1 -*-

"""
Hexagone class - contains everything usefull to manage hexs

Catanyste - Copyright 2008-2009 Julien RAIGNEAU
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance 
with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
the specific language governing permissions and limitations under the License. 
"""   

__author__ = "Vincent"
__date__ = "$1 mars 2009 13:41:04$"

"""
COMPONENTES IN THE CATANE GAME
resource_fields 37 + 15
 * earth
   * lumber 4 + 2
   * brick 3 + 2
   * wool 4 + 2
   * grain 4 + 2
   * ore 3 + 2
   * desert 1 + 1
 * sea
   * water 9 + 2
   * port3 4 + 1
   * port2
     * port2lumber 1
     * port2brick 1
     * port2wool 1 + 1
     * port2grain 1
     * port2ore 1
cards
 * resource cards
   * lumber 19
   * brick 19
   * wool 19
   * grain 19
   * ore 19
 * development cards
   * knight cards 14
   * victory point cards 5
   * others 6
     * requisition 2
     * build road 2
     * free resources 2
certificates 2
 * longest road 1
 * almighty knight 1
set of pawns 4 + 2
 * roads set*15
 * villages set*5
 * cities set*4
thief 1
numbered chips
 * A = 5
 * B = 2
 * C = 6
 * D = 3
 * E = 8
 * F = 10
 * G = 9
 * H = 12
 * I = 11
 * J = 4
 * K = 8
 * L = 10
 * M = 9
 * N = 4
 * O = 5
 * P = 6
 * Q = 3
 * R =11
"""
import copy
import random

class GameComponents:
    """
    Class holding all game components according to number of players
    usage : game_components = GameComponents(number_of_players)
    """
    #number of players (default = 4)
    number_of_players = 4

    #resources constantes
    resource_fields = {}
    """
    resource_fields = {'resource_type':nb_resource}
    """
    EARTH_FIELDS = 'earth_fields'
    LUMBER = 'lumber'
    BRICK = 'brick'
    WOOL = 'wool'
    GRAIN = 'grain'
    ORE = 'ore'
    DESERT = 'desert'
    SEA_FIELDS = 'sea_fields'
    WATER = 'water'
    PORT3 = 'port3'
    PORT2 = 'port2'
    PORT2LUMBER = 'port2lumber'
    PORT2BRICK = 'port2brick'
    PORT2WOOL = 'port2wool'
    PORT2GRAIN = 'port2grain'
    PORT2ORE = 'port2ore'

    #cards
    RESOURCE_CARDS = 'resource_cards'
    DEVELOPMENT_CARDS = 'development cards'
    KNIGHT_CARDS = 'knight cards'
    VICTORY_CARDS = 'victory cards'
    MISCELLANOUS_CARDS = 'miscellanous cards'
    MONOPOLY_CARDS = 'monopoly cards'
    TWO_ROAD_CARDS = 'two road cards'
    TWO_RESOURCE_CARDS = 'two resource cards'
    cards = {RESOURCE_CARDS:{
                         LUMBER:19,
                         BRICK:19,
                         WOOL:19,
                         GRAIN:19,
                         ORE:19},
              DEVELOPMENT_CARDS:{
                         KNIGHT_CARDS:14,
                         VICTORY_CARDS:5,
                         MISCELLANOUS_CARDS:{
                                MONOPOLY_CARDS:2,
                                TWO_ROAD_CARDS:2,
                                TWO_RESOURCE_CARDS:2}}}
    """
    cards = {'card_type':nb_cards}
    """

    #certificates
    LONGEST_ROAD = 'longest road'
    ALMIGHTY_KNIGHT = 'almighty'

    #chip list
    chips = (5,2,6,3,8,10,9,12,11,4,8,10,9,4,5,6,3,11)

    def __init__(self, number_of_players=4):
        """
        number_of_players as integer from 2 to 4
        resource_field as dictionnary
        cards as dictionnary
        chips as tuple
        """

        self.number_of_players = number_of_players

        #set modificators according to number of players
        if 0 < number_of_players <= 4:
            more = 0
        elif 5 <= number_of_players <= 6:
            more = 1

        #set the resources
        self.resource_fields = {self.EARTH_FIELDS:{
                                     self.LUMBER:4+more*2,
                                     self.BRICK:3+more*2,
                                     self.WOOL:4+more*2,
                                     self.GRAIN:4+more*2,
                                     self.ORE:3+more*2,
                                     self.DESERT:1+more},
                                 self.SEA_FIELDS:{
                                     self.WATER:9+more*2,
                                     self.PORT3:4+more,
                                     self.PORT2:{
                                         self.PORT2LUMBER:1,
                                         self.PORT2BRICK:1,
                                         self.PORT2WOOL:1+more,
                                         self.PORT2GRAIN:1,
                                         self.PORT2ORE:1}}}
        self.resource_fields = copy.copy(self.resource_fields)

class ResourceFieldManager:
    """
    Class to manage resource fields according to number of available resource fields
    takeResourceField('resource') return 'resource'
    giveResourceField('resource') return 'resource'
    """

    resource_fields_ref = None
    resource_fields = None

    def __init__(self, number_of_players=4):
        components = GameComponents(number_of_players)
        self.resource_fields_ref = components.resource_fields
        self.resource_fields = dict(components.resource_fields) #working copy

    def __doResourceField(self,resource, i):
        #allow add 1 or take 1
        if i != 1 and i!=-1: return None
        #some constants to improve code readibility
        EARTH_FIELDS = GameComponents.EARTH_FIELDS
        SEA_FIELDS = GameComponents.SEA_FIELDS
        PORT2 = GameComponents.PORT2
        PORT3 = GameComponents.PORT3
        WATER = GameComponents.WATER
        #resource might be earth_fields resources
        if resource in self.resource_fields[EARTH_FIELDS]:
            if -i <= self.resource_fields[EARTH_FIELDS][resource] <= self.resource_fields_ref[EARTH_FIELDS][resource] -i:
                self.resource_fields[EARTH_FIELDS][resource] = self.resource_fields[EARTH_FIELDS][resource] +i
                return resource
        #resource might be port2 resources
        elif resource in self.resource_fields[SEA_FIELDS][PORT2]:
            if -i <= self.resource_fields[SEA_FIELDS][PORT2][resource] <= self.resource_fields_ref[SEA_FIELDS][PORT2][resource] -i:
                self.resource_fields[SEA_FIELDS][PORT2][resource] = self.resource_fields[SEA_FIELDS][PORT2][resource] +i
                return resource
        #resource might be port3
        elif resource == PORT3:
            if -i <= self.resource_fields[SEA_FIELDS][PORT3] <= self.resource_fields_ref[SEA_FIELDS][PORT3] -i:
                self.resource_fields[SEA_FIELDS][PORT3] = self.resource_fields[SEA_FIELDS][PORT3] +i
                return resource
        #resource might be plain water
        elif resource == WATER:
            if -i <= self.resource_fields[SEA_FIELDS][WATER] <= self.resource_fields_ref[SEA_FIELDS][WATER] -i:
                self.resource_fields[SEA_FIELDS][WATER] = self.resource_fields[SEA_FIELDS][WATER] +i
                return resource

        else: return None

    def giveResourceField(self,resource):
        """
        Give back 'resource_name' and remember
        return 'resource_name'
        """
        return self.__doResourceField(resource,1)

    def takeResourceField(self,resource):
        """
        Take 'resource_name' and remember
        return 'resource_name'
        """
        return self.__doResourceField(resource,-1)

    def takeRandomEarthField(self):
        """
        Take a random 'resource_name' of earth type and remember
        return 'resource_name'
        """
        #try to take a random resource among remaining (>0 in dictionary)
        li = self.resource_fields[GameComponents.EARTH_FIELDS].keys()
        #remove if value 0 in dictionary
        for resource in li[:]: #use a copy of li because of li.remove
            if self.resource_fields[GameComponents.EARTH_FIELDS][resource] < 1:
                li.remove(resource)
        #if empty return
        if li == []:return None
        #return random element among remaining
        return self.takeResourceField(li[random.randint(0, len(li)-1)])

    def takeRandomSeaField(self):
        """
        Take a random 'resource_name' of sea type and remember
        return 'resource_name'
        """
        #some constants to improve code readibility
        SEA_FIELDS = GameComponents.SEA_FIELDS
        PORT2 = GameComponents.PORT2
        #sea_fields and subcase port2
        li1 = self.resource_fields[SEA_FIELDS].keys()
        li2 = self.resource_fields[SEA_FIELDS][PORT2].keys()
        #remove if value 0 in dictionary
        for resource in li1[:]: #use a copy of li because of li.remove
            if self.resource_fields[SEA_FIELDS][resource] < 1:
                li1.remove(resource)
        li1.remove(PORT2)
        for resource in li2[:]: #use a copy of li because of li.remove
            if self.resource_fields[SEA_FIELDS][PORT2][resource] < 1:
                li2.remove(resource)
        #if empty return
        li = li1 + li2
        if li == []: return None
        #return random element among remaining
        a = li[random.randint(0, len(li)-1)]
        b = self.takeResourceField(a)
        if not b:
            print 'a : ',a,'b : ',b, '\n'
        return b  
    
if __name__ == "__main__":
    #testing
    compo = GameComponents()
    print compo.resource_fields, '\n'
    print compo.cards, '\n'
    print compo.chips,'\n'
    m = ResourceFieldManager()
    print 'resource_fields : ',m.resource_fields,'\n'
    print 'resource_fields_ref : ',m.resource_fields_ref,'\n'
    r = range(20)
    for i in r:
        print 'random earth : ' , m.takeRandomEarthField(),"\trandom sea : ",m.takeRandomSeaField(),'\n'
    print 'resource_fields : ',m.resource_fields,'\n'
    print 'resource_fields_ref : ',m.resource_fields_ref,'\n'

    print '----------take ORE-------\n'
    m.takeResourceField(GameComponents.ORE)
    print 'resource_fields : ',m.resource_fields,'\n'
    print '------give LUMBER------\n'
    m.giveResourceField(GameComponents.LUMBER)
    print 'resource_fields : ',m.resource_fields,'\n'


